#include "..\..\Header\System\collision.h"
using namespace std;
inline sf::Vector2f RotationPoint(const sf::Vector2f& Point, float Angle)
{
   Angle = Angle * (Pi/180.0);
    sf::Vector2f RotatedPoint;
    RotatedPoint.x = Point.x * cos(Angle) + Point.y * sin(Angle);
    RotatedPoint.y = -Point.x * sin(Angle) + Point.y * cos(Angle);
    return RotatedPoint;
}

int CollisionBoiteSensible( sf::Sprite& Texture1,  sf::Sprite& Texture2)
{
   sf::Rect<float> boite1;
   boite1.left   = Texture1.getPosition().x - Texture1.getOrigin().x * Texture1.getScale().x;
   boite1.top    = Texture1.getPosition().y - Texture1.getOrigin().y * Texture1.getScale().y;
   boite1.width  = Texture1.getPosition().x + Texture1.getLocalBounds().width - Texture1.getOrigin().x * Texture1.getLocalBounds().width;
   boite1.height = Texture1.getPosition().y + Texture1.getLocalBounds().height - Texture1.getOrigin().y * Texture1.getLocalBounds().height;

   if(Texture1.getRotation() != 0.f)
   {
      sf::Vector2f pt_A, pt_B, pt_C, pt_D;

      pt_A.x = boite1.left;
      pt_A.y = boite1.height;

      pt_B.x = boite1.left;
      pt_B.y = boite1.top;

      pt_C.x = boite1.width;
      pt_C.y = boite1.top;

      pt_D.x = boite1.width;
      pt_D.y = boite1.height;

      //Rotation

      sf::Vector2f pt_Ar, pt_Br, pt_Cr, pt_Dr;
      pt_Ar.x = 0;
      pt_Ar.y = Texture1.getLocalBounds().height;

      pt_Br.x = 0;
      pt_Br.y = 0;

      pt_Cr.x = Texture1.getLocalBounds().width;
      pt_Cr.y = 0;

      pt_Dr.x = Texture1.getLocalBounds().width;
      pt_Dr.y = Texture1.getLocalBounds().height;


      pt_A = RotationPoint(pt_Ar, Texture1.getRotation());
      pt_B = RotationPoint(pt_Br, Texture1.getRotation());
      pt_C = RotationPoint(pt_Cr, Texture1.getRotation());
      pt_D = RotationPoint(pt_Dr, Texture1.getRotation());

      sf::Vector2f centre;
      centre.x = Texture1.getOrigin().x * Texture1.getScale().x;
      centre.y = Texture1.getOrigin().y * Texture1.getScale().y;
      centre = RotationPoint(centre, Texture1.getRotation());

      pt_A += Texture1.getPosition() - centre;
      pt_B += Texture1.getPosition() - centre;
      pt_C += Texture1.getPosition() - centre;
      pt_D += Texture1.getPosition() - centre;


      sf::Vector2f pt_Af, pt_Bf, pt_Cf, pt_Df;

      pt_Af = pt_A;
      pt_Af = ((pt_Af.x < pt_B.x)? pt_Af : pt_B);
      pt_Af = ((pt_Af.x < pt_C.x)? pt_Af : pt_C);
      pt_Af = ((pt_Af.x < pt_D.x)? pt_Af : pt_D);

      pt_Bf = pt_A;
      pt_Bf = ((pt_Bf.y < pt_B.y)? pt_Bf : pt_B);
      pt_Bf = ((pt_Bf.y < pt_C.y)? pt_Bf : pt_C);
      pt_Bf = ((pt_Bf.y < pt_D.y)? pt_Bf : pt_D);

      pt_Cf = pt_A;
      pt_Cf = ((pt_Cf.x > pt_B.x)? pt_Cf : pt_B);
      pt_Cf = ((pt_Cf.x > pt_C.x)? pt_Cf : pt_C);
      pt_Cf = ((pt_Cf.x > pt_D.x)? pt_Cf : pt_D);

      pt_Df = pt_A;
      pt_Df = ((pt_Df.y > pt_B.y)? pt_Df : pt_B);
      pt_Df = ((pt_Df.y > pt_C.y)? pt_Df : pt_C);
      pt_Df = ((pt_Df.y > pt_D.y)? pt_Df : pt_D);



      boite1.left   = pt_Af.x;
      boite1.top    = pt_Bf.y;
      boite1.width  = pt_Cf.x;
      boite1.height = pt_Df.y;
   }

   sf::Rect<float> boite2;
   boite2.left   = Texture2.getPosition().x - Texture2.getOrigin().x * Texture2.getScale().x;
   boite2.top    = Texture2.getPosition().y - Texture2.getOrigin().y * Texture2.getScale().y;
   boite2.width  = Texture2.getPosition().x + Texture2.getLocalBounds().width - Texture2.getOrigin().x * Texture2.getScale().x;
   boite2.height = Texture2.getPosition().y + Texture2.getLocalBounds().height - Texture2.getOrigin().y * Texture2.getScale().y;


   if(Texture2.getRotation() != 0.f) //Si l'angle est different, on doit recalculer les boites
   {
      sf::Vector2f pt_A, pt_B, pt_C, pt_D;

      //Schema des points du carrée
      // B_____C
      // |     |
      // |     |
      // A_____D


      pt_A.x = boite2.left;
      pt_A.y = boite2.height;

      pt_B.x = boite2.left;
      pt_B.y = boite2.top;

      pt_C.x = boite2.width;
      pt_C.y = boite2.top;

      pt_D.x = boite2.width;
      pt_D.y = boite2.height;

      //Rotation

      sf::Vector2f pt_Ar, pt_Br, pt_Cr, pt_Dr;
      pt_Ar.x = 0;
      pt_Ar.y = Texture2.getLocalBounds().height;

      pt_Br.x = 0;
      pt_Br.y = 0;

      pt_Cr.x = Texture2.getLocalBounds().width;
      pt_Cr.y = 0;

      pt_Dr.x = Texture2.getLocalBounds().width;
      pt_Dr.y = Texture2.getLocalBounds().height;


      pt_A = RotationPoint(pt_Ar, Texture2.getRotation());
      pt_B = RotationPoint(pt_Br, Texture2.getRotation());
      pt_C = RotationPoint(pt_Cr, Texture2.getRotation());
      pt_D = RotationPoint(pt_Dr, Texture2.getRotation());

      sf::Vector2f centre;
      centre.x = Texture2.getOrigin().x * Texture2.getScale().x;
      centre.y = Texture2.getOrigin().y * Texture2.getScale().y;
      centre = RotationPoint(centre, Texture2.getRotation());

      pt_A += Texture2.getPosition() - centre;
      pt_B += Texture2.getPosition() - centre;
      pt_C += Texture2.getPosition() - centre;
      pt_D += Texture2.getPosition() - centre;


      sf::Vector2f pt_Af, pt_Bf, pt_Cf, pt_Df;

      //Schema des points du carrée après rotation
      /*
      //     Bf
      //    /  \
      //  Af    Cf
      //    \  /
      //     Df
        */
      //Utilisation de l'operateur ? : condition ? valeur_vrai : valeur_faux;

      pt_Af = pt_A;
      pt_Af = ((pt_Af.x < pt_B.x)? pt_Af : pt_B);
      pt_Af = ((pt_Af.x < pt_C.x)? pt_Af : pt_C);
      pt_Af = ((pt_Af.x < pt_D.x)? pt_Af : pt_D);

      pt_Bf = pt_A;
      pt_Bf = ((pt_Bf.y < pt_B.y)? pt_Bf : pt_B);
      pt_Bf = ((pt_Bf.y < pt_C.y)? pt_Bf : pt_C);
      pt_Bf = ((pt_Bf.y < pt_D.y)? pt_Bf : pt_D);

      pt_Cf = pt_A;
      pt_Cf = ((pt_Cf.x > pt_B.x)? pt_Cf : pt_B);
      pt_Cf = ((pt_Cf.x > pt_C.x)? pt_Cf : pt_C);
      pt_Cf = ((pt_Cf.x > pt_D.x)? pt_Cf : pt_D);

      pt_Df = pt_A;
      pt_Df = ((pt_Df.y > pt_B.y)? pt_Df : pt_B);
      pt_Df = ((pt_Df.y > pt_C.y)? pt_Df : pt_C);
      pt_Df = ((pt_Df.y > pt_D.y)? pt_Df : pt_D);


      //Schema des points du carrée après rotation
      //   __Bf__
      //  | /  \ |
      //  Af    Cf
      //  | \  / |
      //   __Df__


      boite2.left   = pt_Af.x;
      boite2.top    = pt_Bf.y;
      boite2.width  = pt_Cf.x;
      boite2.height = pt_Df.y;
   }
   if(boite1.intersects(boite2)) //S il y a une intersection
   {
      sf::Vector2f Centre;

      Centre.x = boite1.left + (boite1.width - boite1.left)/2.f;
      Centre.y = boite1.top + (boite1.height - boite1.top)/2.f;

      //On prend le centre de l'objet de réference

      //Schema de la technique de visualisation
      //
      //      |     |
      //  135°| 90° | 45°
      //  ____B_____C____
      //      |     |
      //  180°|     | 0°
      //  ____A_____D____
      //      |     |
      //  225°| 270°| 315°
      //
      //On cherche la zone où se trouve le centre de l'objet de reference

      if(Centre.x <= boite2.left)
      {
         if(Centre.y <= boite2.top)
         {
            return 135;
         }
         else if(Centre.y >= boite2.height)
         {
            return 225;
         }
         else
         {
            return 180;
         }
      }
      else if(Centre.x >= boite2.width)
      {
         if(Centre.y <= boite2.top)
         {
            return 45;
         }
         else if(Centre.y >= boite2.height)
         {
            return 315;
         }
         else
         {
            return 0;
         }
      }
      else
      {
         if(Centre.y <= boite2.top)
         {
            return 90;
         }
         else if(Centre.y >= boite2.height)
         {
            return 270;
         }
         else
         {
            //Cas "parfait" -> toutes directions = 360 (cas normal de 0 à 359)
            return 360;
         }
      }
   }

   //Si valeur négative, pas de collision
   return -1;
}

bool CollisionBoiteVector( sf::Sprite& Texture1,  sf::Vector2f position)
{
   sf::Rect<float> boite1;
   boite1.left   = Texture1.getPosition().x - Texture1.getOrigin().x * Texture1.getScale().x;
   boite1.top    = Texture1.getPosition().y - Texture1.getOrigin().y * Texture1.getScale().y;
   boite1.width  = Texture1.getPosition().x + Texture1.getLocalBounds().width - Texture1.getOrigin().x * Texture1.getScale().x;
   boite1.height = Texture1.getPosition().y + Texture1.getLocalBounds().height - Texture1.getOrigin().y * Texture1.getScale().y;

   if(Texture1.getRotation() != 0.f)
   {
      sf::Vector2f pt_A, pt_B, pt_C, pt_D;

      pt_A.x = boite1.left;
      pt_A.y = boite1.height;

      pt_B.x = boite1.left;
      pt_B.y = boite1.top;

      pt_C.x = boite1.width;
      pt_C.y = boite1.top;

      pt_D.x = boite1.width;
      pt_D.y = boite1.height;

      //Rotation

      sf::Vector2f pt_Ar, pt_Br, pt_Cr, pt_Dr;
      pt_Ar.x = 0;
      pt_Ar.y = Texture1.getLocalBounds().height;

      pt_Br.x = 0;
      pt_Br.y = 0;

      pt_Cr.x = Texture1.getLocalBounds().width;
      pt_Cr.y = 0;

      pt_Dr.x = Texture1.getLocalBounds().width;
      pt_Dr.y = Texture1.getLocalBounds().height;


      pt_A = RotationPoint(pt_Ar, Texture1.getRotation());
      pt_B = RotationPoint(pt_Br, Texture1.getRotation());
      pt_C = RotationPoint(pt_Cr, Texture1.getRotation());
      pt_D = RotationPoint(pt_Dr, Texture1.getRotation());

      sf::Vector2f centre;
      centre.x = Texture1.getOrigin().x * Texture1.getScale().x;
      centre.y = Texture1.getOrigin().y * Texture1.getScale().y;
      centre = RotationPoint(centre, Texture1.getRotation());

      pt_A += Texture1.getPosition() - centre;
      pt_B += Texture1.getPosition() - centre;
      pt_C += Texture1.getPosition() - centre;
      pt_D += Texture1.getPosition() - centre;


      sf::Vector2f pt_Af, pt_Bf, pt_Cf, pt_Df;

      pt_Af = pt_A;
      pt_Af = ((pt_Af.x < pt_B.x)? pt_Af : pt_B);
      pt_Af = ((pt_Af.x < pt_C.x)? pt_Af : pt_C);
      pt_Af = ((pt_Af.x < pt_D.x)? pt_Af : pt_D);

      pt_Bf = pt_A;
      pt_Bf = ((pt_Bf.y < pt_B.y)? pt_Bf : pt_B);
      pt_Bf = ((pt_Bf.y < pt_C.y)? pt_Bf : pt_C);
      pt_Bf = ((pt_Bf.y < pt_D.y)? pt_Bf : pt_D);

      pt_Cf = pt_A;
      pt_Cf = ((pt_Cf.x > pt_B.x)? pt_Cf : pt_B);
      pt_Cf = ((pt_Cf.x > pt_C.x)? pt_Cf : pt_C);
      pt_Cf = ((pt_Cf.x > pt_D.x)? pt_Cf : pt_D);

      pt_Df = pt_A;
      pt_Df = ((pt_Df.y > pt_B.y)? pt_Df : pt_B);
      pt_Df = ((pt_Df.y > pt_C.y)? pt_Df : pt_C);
      pt_Df = ((pt_Df.y > pt_D.y)? pt_Df : pt_D);



      boite1.left   = pt_Af.x;
      boite1.top    = pt_Bf.y;
      boite1.width  = pt_Cf.x;
      boite1.height = pt_Df.y;
   }

   if(boite1.contains(position.x, position.y)) //S il y a une intersection
   {
      return true;
   }

   //Si valeur négative, pas de collision
   return false;
}
std::string to_string(int nombre)
{
    ostringstream oss;
    oss.str("");
    oss << nombre;
    return oss.str();
}
double interpolation_linaire(double a, double b, double x)
{
    return a * (1-x) + b*x;
}
double interpolation_cos(double a, double b, double x,int pas)
{
    double k = (1-cos(x*Pi))/2;
    return interpolation_linaire(a,b,k);
}
std::string narrow(const std::wstring& ws)
{
    std::vector<char> buffer(ws.size());
    std::locale loc("english");
    std::use_facet< std::ctype<wchar_t> >(loc).narrow(ws.data(), ws.data() + ws.size(), '?', &buffer[0]);

    return std::string(&buffer[0], buffer.size());
}
bool is_readable( const std::string & file )
{
    std::ifstream fichier( file.c_str() );
    return !fichier.fail();
}
bool is_in(float x, float a, float b)
{
    if(x > a && x < b)
    {
        return true;
    }
    else
    {
        return false;
    }
}
